/*!
实现base64编解码
!*/
use std::collections::HashMap;


///编码
pub fn encode_base64(s: &String) -> String {
    //基础字符串 64个字符，转u8数组
    let  base =  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".as_bytes().to_vec();
    let str_len = s.len(); //字节长度
    let bytes = s.as_bytes().to_vec(); //转数组

    //空字符串
    let mut rs = String::new();

    //索引
    let mut i = 0;

    //3个字符为一组，转成4个base64的字符
    let mut u1  = 0;
    let mut u2  =  0;
    let mut u3  = 0;

    while i < str_len {
        u1 = bytes[i]; //第一个字符
        if i + 1 < str_len { //是否为最后一个字符
            u2 = bytes[i + 1];
        }else {
            u2 = 0;
        }
        if i + 2 < str_len { //是否为最后一个字符
            u3 = bytes[i + 2];
        }else {
            u3 = 0;
        }

        //取出第一个字符的前6位并找出对应的结果字符
        rs.push(  base[(u1 >> 2) as usize] as char);

        //将第一个字符的后两位与第二个字符的前4位进行组合并找到对应的结果字符
        let x2 = ((u1 & 0x3_u8) << 4) | (u2 >> 4);
        let x = base[x2 as usize];
        rs.push(x as char);

        if u2 == 0{
            rs.push('='); //填充
        }else {
            //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
            rs.push(base[(((u2 & 0xf_u8 )<< 2) | (u3 >> 6))as usize] as char);
        }

        if u3 == 0 {
            rs.push('='); //填充
        }else {
            //取出第三个字符的后6位并找出结果字符
            rs.push(base[(u3 & 0x3f_u8) as usize] as char);
        }
        i += 3; //下一组

    }
    return rs;

}
///解码
pub fn base64_decode(base64: &String) -> String{
    //根据base64表，以字符找到对应的十进制数据
    let  base =  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".as_bytes().to_vec();
    let  mut map: HashMap<u8, u8>  = HashMap::with_capacity(64);
    let mut i = 0;
    for  c in base {
        map.insert(c, i);
        i += 1;
    }
    //base64字符串转字节数组
    let bytes = base64.as_bytes().to_vec();

    //解码后的字节数组
    let mut v: Vec<u8> = Vec::with_capacity(base64.len() / 4 * 3);
    let mut i: usize = 0; //索引

    //字节4个一组 转成3个字节
    let mut u1: u8 = 0;
    let mut u2: u8 = 0;
    let mut u3: u8 = 0;
    let mut u4: u8 = 0;

    //base64字符对应的索引位置（数字）
    let mut index1: u8 = 0;
    let mut index2: u8 = 0;
    let mut index3: u8 = 0;
    let mut index4: u8 = 0;
    while i < bytes.len() {
        u1 = bytes[i];
        u2 = bytes[i+1];
        u3 = bytes[i+2];
        u4 = bytes[i+3];

        index1 = * map.get(&u1).unwrap();
        index2 = * map.get(&u2).unwrap();
        if u3 == '=' as u8 { //填充字符
            index3 = 0;
        }else {
            index3 = * map.get(&u3).unwrap();
        }
        if u4 == '=' as u8 {
            index4 = 0;
        }else {
            index4 = * map.get(&u4).unwrap();
        }

        //println!("index1={}, index2={},index3={},index4={} ", index1, index2, index3, index4);
        //第一个字节取后6位,第二个数字取前4位（高两位始终是填充的0,不算，所以取4个位）
        v.push((index1 << 2) | (index2 >> 4));

        //第二个字节取后4位，第三个字节取前6位
        v.push((index2 << 4) | (index3 >> 2));
        //第三个字节取后2位，第4个字节串取前8位
        v.push((index3 << 6) | (index4));

        i += 4;
    }
    //将字节数组转字符串
    return String::from_utf8(v).unwrap();
}

#[test]
pub fn encode_test(){
    let s = encode_base64(&("你好,i am you".to_string()));
    println!("{}", &s);
}
#[test]
pub fn decode_test(){
    let s = String::from("5L2g5aW9LGkgYW0geW91MzQ=");
    let s = base64_decode(&s);
    println!("{}", s);
}